<template>
    <view class="van-stepper">
        <button class="van-stepper__minus" :class="{'van-stepper__minus--disabled': minusDisabled}" @tap="onChange('minus')"></button>
        <input class="van-stepper__input" type="number" v-model="currentValue" :disabled="disabled || disableInput"
            :style="{ width: this.inputWidth }" @input="onInput" @focus="onFocus" @blur="onBlur" />
        <button class="van-stepper__plus" :class="{'van-stepper__plus--disabled': plusDisabled}" @tap="onChange('plus')"></button>
    </view>
</template>

<script>
    function isDef(value) {
        return value !== undefined && value !== null;
    }
    export default {
        name: 'yhgStepper',
        props: {
            value: null,
            integer: Boolean,
            disabled: Boolean,
            inputWidth: String,
            asyncChange: Boolean,
            disableInput: Boolean,
            min: {
                type: [String, Number],
                default: 1
            },
            max: {
                type: [String, Number],
                default: Infinity
            },
            step: {
                type: [String, Number],
                default: 1
            },
            defaultValue: {
                type: [String, Number],
                default: 1
            }
        },

        data() {
            const value = this.range(isDef(this.value) ? this.value : this.defaultValue);
            if (value !== +this.value) {
                this.$emit('input', value);
            }

            return {
                currentValue: value
            };
        },

        computed: {
            minusDisabled() {
                return this.disabled || this.currentValue <= this.min;
            },

            plusDisabled() {
                return this.disabled || this.currentValue >= this.max;
            }
        },

        watch: {
            value(val) {
                if (val !== this.currentValue) {
                    this.currentValue = this.format(val);
                }
            },

            currentValue(val) {
                this.$emit('input', val);
                this.$emit('change', val);
            }
        },

        methods: {
            // filter illegal characters
            format(value) {
                value = String(value).replace(/[^0-9.-]/g, '');
                return value === '' ? 0 : this.integer ? Math.floor(value) : +value;
            },

            // limit value range
            range(value) {
                return Math.max(Math.min(this.max, this.format(value)), this.min);
            },

            onInput(event) {
                const {
                    value
                } = event.target;
                const formatted = this.format(value);

                if (!this.asyncChange) {
                    if (+value !== formatted) {
                        event.target.value = formatted;
                    }
                    this.currentValue = formatted;
                } else {
                    event.target.value = this.currentValue;
                    this.$emit('input', formatted);
                    this.$emit('change', formatted);
                }
            },

            onChange(type) {
                if (this[`${type}Disabled`]) {
                    this.$emit('overlimit', type);
                    return;
                }

                const diff = type === 'minus' ? -this.step : +this.step;
                const value = Math.round((this.currentValue + diff) * 100) / 100;

                if (!this.asyncChange) {
                    this.currentValue = this.range(value);
                } else {
                    this.$emit('input', value);
                    this.$emit('change', value);
                }
                this.$emit(type);
            },

            onFocus(event) {
                this.$emit('focus', event);
            },

            onBlur(event) {
                this.currentValue = this.range(this.currentValue);
                this.$emit('blur', event);

                // fix edge case when input is empty and min is 0
                if (this.currentValue === 0) {
                    event.target.value = this.currentValue;
                }
            }
        },

    };
</script>

<style>
    .van-stepper {
        display: flex;
        font-size: 0;
        -webkit-user-select: none;
        user-select: none;
    }

    .van-stepper__minus,
    .van-stepper__plus {
        position: relative;
        box-sizing: border-box;
        width: 28px;
        height: 28px;
        margin: 0;
        padding: 0;
        color: #323233;
        vertical-align: middle;
        background-color: #f2f3f5;
        border: 0;
        cursor: pointer;
    }

    .van-stepper__minus::before,
    .van-stepper__plus::before {
        width: 50%;
        height: 1px;
    }

    .van-stepper__minus::after,
    .van-stepper__plus::after {
        width: 1px;
        height: 50%;
    }

    .van-stepper__minus::before,
    .van-stepper__plus::before,
    .van-stepper__minus::after,
    .van-stepper__plus::after {
        position: absolute;
        top: 50%;
        left: 50%;
        background-color: currentColor;
        -webkit-transform: translate(-50%, -50%);
        transform: translate(-50%, -50%);
        content: '';
    }

    .van-stepper__minus:active,
    .van-stepper__plus:active {
        background-color: #e8e8e8;
    }

    .van-stepper__minus--disabled,
    .van-stepper__plus--disabled {
        color: #c8c9cc;
        background-color: #f7f8fa;
        cursor: not-allowed;
    }

    .van-stepper__minus--disabled:active,
    .van-stepper__plus--disabled:active {
        background-color: #f7f8fa;
    }

    .van-stepper__minus {
        border-radius: 4px 0 0 4px;
    }

    .van-stepper__minus::after {
        display: none;
    }

    .van-stepper__plus {
        border-radius: 0 4px 4px 0;
    }

    .van-stepper__input {
        box-sizing: border-box;
        width: 32px;
        height: 28px;
        margin: 0 2px;
        padding: 0;
        color: #323233;
        font-size: 14px;
        line-height: normal;
        text-align: center;
        vertical-align: middle;
        background-color: #f2f3f5;
        border: 0;
        border-width: 1px 0;
        border-radius: 0;
        -webkit-appearance: none;
    }

    .van-stepper__input:disabled {
        color: #c8c9cc;
        background-color: #f2f3f5;
        -webkit-text-fill-color: currentColor;
        opacity: 1;
    }

    .van-stepper__input:read-only {
        cursor: default;
    }

    .van-stepper--round .van-stepper__input {
        background-color: transparent;
    }

    .van-stepper--round .van-stepper__plus,
    .van-stepper--round .van-stepper__minus {
        border-radius: 100%;
    }

    .van-stepper--round .van-stepper__plus:active,
    .van-stepper--round .van-stepper__minus:active {
        opacity: 0.7;
    }

    .van-stepper--round .van-stepper__plus--disabled,
    .van-stepper--round .van-stepper__minus--disabled,
    .van-stepper--round .van-stepper__plus--disabled:active,
    .van-stepper--round .van-stepper__minus--disabled:active {
        opacity: 0.3;
    }

    .van-stepper--round .van-stepper__plus {
        color: #fff;
        background-color: #ee0a24;
    }

    .van-stepper--round .van-stepper__minus {
        color: #ee0a24;
        background-color: #fff;
        border: 1px solid #ee0a24;
    }
</style>
